<?
/**
* <b>payPal</b>
*
* Handy PayPal API Links:
* Variable Names/Meanings: https://www.paypal.com/IntegrationCenter/ic_std-variable-ref-buy-now.html#HTMLVariablesOnlyforBuyNowButtons

/*******************************************************************************
 *                      PHP Paypal IPN Integration Class
 *******************************************************************************
 *      Author:     Micah Carrick
 *      Email:      email@micahcarrick.com
 *      Website:    http://www.micahcarrick.com
 *
 *      File:       paypal.class.php
 *      Version:    1.00
 *      Copyright:  (c) 2005 - Micah Carrick 
 *                  You are free to use, distribute, and modify this software 
 *                  under the terms of the GNU General Public License.  See the
 *                  included license.txt file.
 *      
 *******************************************************************************
 *  VERION HISTORY:
 *  
 *      v1.0.0 [04.16.2005] - Initial Version
 *
 *******************************************************************************
 *  DESCRIPTION:
 *
 *      This file provides a neat and simple method to interface with paypal and
 *      The paypal Instant Payment Notification (IPN) interface.  This file is
 *      NOT intended to make the paypal integration "plug 'n' play". It still
 *      requires the developer (that should be you) to understand the paypal
 *      process and know the variables you want/need to pass to paypal to
 *      achieve what you want.  
 *
 *      This class handles the submission of an order to paypal aswell as the
 *      processing an Instant Payment Notification.
 *  
 *      This code is based on that of the php-toolkit from paypal.  I've taken
 *      the basic principals and put it in to a class so that it is a little
 *      easier--at least for me--to use.  The php-toolkit can be downloaded from
 *      http://sourceforge.net/projects/paypal.
 *      
 *      To submit an order to paypal, have your order form POST to a file with:
 *
 *          $p = new paypal_class;
 *          $p->addField('business', 'somebody@domain.com');
 *          $p->addField('first_name', $_POST['first_name']);
 *          ... (add all your fields in the same manor)
 *          $p->submit_paypal_post();
 *
 *      To process an IPN, have your IPN processing file contain:
 *
 *          $p = new paypal_class;
 *          if ($p->validateIpn()) {
 *          ... (IPN is verified.  Details are in the data() array)
 *          }
 *
 *
 *      In case you are new to paypal, here is some information to help you:
 *
 *      1. Download and read the Merchant User Manual and Integration Guide from
 *         http://www.paypal.com/en_US/pdf/integration_guide.pdf.  This gives 
 *         you all the information you need including the fields you can pass to
 *         paypal (using addField() with this class) aswell as all the fields
 *         that are returned in an IPN post (stored in the data() array in
 *         this class).  It also diagrams the entire transaction process.
 *
 *      2. Create a "sandbox" account for a buyer and a seller.  This is just
 *         a test account(s) that allow you to test your site from both the 
 *         seller and buyer perspective.  The instructions for this is available
 *         at https://developer.paypal.com/ as well as a great forum where you
 *         can ask all your paypal integration questions.  Make sure you follow
 *         all the directions in setting up a sandbox test environment, including
 *         the addition of fake bank accounts and credit cards.
 * 
 *******************************************************************************
*
* @package gravy.plugins
* @class payPal extends errorHandler
* @author Micah Carrick
*/

class gPayPal extends model{
	public $ipnResponse="";									// holds the IPN response from paypal   
	public $lastError="";									// The last IPN Error
	public $data = array();									// array contains the POST values for IPN
	public $fields = array();								// array holds the fields to submit to paypal
	public $useSandbox=true;									// A flag to say whether to use the Sandbox environment or not.
	public $url="https://www.paypal.com/cgi-bin/webscr";			// The PayPal URL
	public $liveUrl="https://www.paypal.com/cgi-bin/webscr";		// The Live PayPal URL
	public $sbUrl="https://www.sandbox.paypal.com/cgi-bin/webscr";	// The Sandbox PayPal URL

	public function __construct($model="paypal"){
		// call the parent constructor
		parent::__construct($model);

		$this->url=($this->useSandbox)?$this->sbUrl:$this->liveUrl;
		$this->ipnResponse="";

		// populate $fields array with a few default values.  See the paypal
		// documentation for a list of fields and their data types. These defaul
		// values can be overwritten by the calling script.
		$this->addField('rm','2'); 	// Return method = POST
		$this->addField('cmd','_xclick'); 
	}

	public function getUrl($useSandbox=NULL){
		if($useSandbox!==NULL){
			$this->useSandbox=$sandbox;
		}
		$this->url=($this->useSandbox)?$this->sbUrl:$this->liveUrl;
		return($this->url);
	}

	public function isLive($isLive=true){
		$this->useSandbox=!$isLive;
		$this->url=($this->useSandbox)?$this->sbUrl:$this->liveUrl;
		return($this->url);
	}

	public function addField($field, $value) {
		
		// adds a key=>value pair to the fields array, which is what will be 
		// sent to paypal as POST variables.  If the value is already in the 
		// array, it will be overwritten.
		$this->fields["$field"] = $value;
	}
	
	public function getField($field) {
		return($this->fields[$field]);
	}
	
	public function outputFormFields() {
		foreach($this->fields as $name=>$value){
			print("<input type=\"hidden\" name=\"$name\" value=\"$value\">".chr(13));
		}
	}
	
	public function validateIpn() {
		$result=false;
		// parse the paypal URL
		$urlParsed=parse_url($this->url);

		$req='cmd=_notify-validate';

		foreach($_POST as $key=>$value){
			$this->set($key,stripslashes($value));
			$value=urlencode(stripslashes($value));
			$req.="&$key=$value";
		}

		// open the connection to paypal
		$url="http://".$urlParsed[host];
		$this->log("payPal::validateIpn::cUrl::url($url)");
		if (!$curl = curl_init()) {
			$this->log("payPal::validateIpn::cUrl::error(Could not initialize cURL session.)");
		}else{
			$this->log("payPal::validateIpn::cUrl::initialised()");
			curl_setopt($curl, CURLOPT_POST, true); // set POST method
			curl_setopt($curl, CURLOPT_URL,$this->getUrl()); // set url
			curl_setopt($curl, CURLOPT_POSTFIELDS, $req); // fields to POST
			curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // return var
			curl_setopt($curl, CURLOPT_TIMEOUT, 30); // time out after 5 secs
			curl_setopt($curl, CURLOPT_FAILONERROR, true);
			curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // allow redirects
			curl_setopt($curl, CURLOPT_FRESH_CONNECT, true); // no caching
			$this->log("payPal::validateIpn::cUrl::optionsSet()");
			$response=curl_exec($curl); // engage!
			$this->log("payPal::validateIpn::cUrl::executed()");

			$curlErrorNum = curl_errno($curl); // save error code; 0=none
			$curlErrorText = curl_error($curl); // save error message; ""=none
			curl_close($curl);
			$this->log("payPal::validateIpn::cUrl::closedCurl(response:$response)");
			if ($curlErrorNum!=0){
				// CURL error
				$this->log("payPal::validateIpn::cUrl::error($curlErrorNum - $curlErrorText.)");
			}elseif($response=="VERIFIED"){
				// check the payment_status is Completed
				$result=true;
				if($_POST["payment_status"]=="Completed"){
					$this->log("payPal::validateIpn::valid(true)");
				}else{
					$this->log("payPal::validateIpn::paymentStatusIncomplete(payment_status==".$_POST["payment_status"].")");
				}
			}elseif($response=="INVALID"){
				$this->log("payPal::validateIpn::invalid(payPal doesn't like your request: $response)");
			}else{
				$this->log("payPal::validateIpn::error(no response... f**k you payPal: $response)");
			}
		}
		return($result);
	}
}         
?>
